package com.anivia.common.log;

import cn.hutool.core.lang.Assert;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.*;

/**
 * 请求
 */
@Slf4j
public class AniviaRequestWrapper extends HttpServletRequestWrapper {

    private AniviaServletInputStream aniviaServletInputStream;

    private BufferedReader bufferedReader;

    private byte[] requestBody;

    public static AniviaRequestWrapper build(HttpServletRequest request) throws IOException {
        if (request instanceof AniviaRequestWrapper) {
            return (AniviaRequestWrapper) request;
        } else {
            return new AniviaRequestWrapper(request);
        }
    }

    private AniviaRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = this.copyToByteArray(request.getInputStream());
    }


    private byte[] copyToByteArray(InputStream in) throws IOException {
        if (in == null) {
            return new byte[0];
        } else {
            ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
            copy((InputStream) in, out);
            return out.toByteArray();
        }
    }

    private int copy(InputStream in, OutputStream out) throws IOException {
        Assert.notNull(in, "No InputStream specified");
        Assert.notNull(out, "No OutputStream specified");
        int byteCount = 0;

        int bytesRead;
        for (byte[] buffer = new byte[4096]; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
            out.write(buffer, 0, bytesRead);
        }

        out.flush();
        return byteCount;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (aniviaServletInputStream == null) {
            aniviaServletInputStream = new AniviaServletInputStream(new ByteArrayInputStream(requestBody));
        }
        return aniviaServletInputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (bufferedReader == null) {
            bufferedReader = new BufferedReader(new InputStreamReader(this.getInputStream()));
        }
        return bufferedReader;
    }

    public byte[] getRequestBody() {
        return this.requestBody;
    }

    public void setRequestBody(byte[] requestBody) {
        this.requestBody = requestBody;
    }

    public void destroy() {
        try {
            if (aniviaServletInputStream != null) {
                aniviaServletInputStream.close();
            }
        } catch (Exception e) {
            log.error("流关闭异常", e);
        }
    }

    @AllArgsConstructor
    public static class AniviaServletInputStream extends ServletInputStream {

        private final ByteArrayInputStream inputStream;

        @Override
        public boolean isFinished() {
            return false;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener readListener) {
        }

        @Override
        public int read() throws IOException {
            return inputStream.read();
        }

        @Override
        public void close() throws IOException {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }
}

